package com.yunqiao.common.pay;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.resource.ClassPathResource;
import cn.hutool.core.lang.Console;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.XmlUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONUtil;
import com.github.binarywang.wxpay.service.WxPayService;
import com.qiniu.util.IOUtils;
import com.yunqiao.common.config.SysConfig;
import com.yunqiao.common.consts.AppConsts;
import com.yunqiao.common.exception.CustomApiException;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;

import javax.annotation.Resource;
import javax.net.ssl.SSLContext;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.security.KeyStore;
import java.util.*;

/**
 * 微信支付模板
 */
public class WxPay {
    //app 用户端端的appId
    private static String userAppid = "wxf143d893f71aa700";
    //app 司机端端的appId
    private static String driverAppid = "wx0afa88fa0692707a";
    //用户端微信小程序 appId
    public static String wx_small_procedures_user_appid = "wxc7acc55d16d05e23";
    //用户端微信小程序 appsecret
    public static String wx_small_procedures_user_appsecret = "6f12b2bc9cc2b732db007d45dcb57bdd";
    //司机端微信小程序 appId
    public static String wx_small_procedures_driver_appid = "wxbe9d5f74a895f02d";
    //司机端微信小程序 appsecret
    public static String wx_small_procedures_driver_appsecret = "91393a61bd11e0b366c50f7ac137612f";
    //商户
    private static String mchId = "1531114251";
    //商户密钥
    private static String key = "0RKlC5Abl34snE6r4LKU7ubAC5M5AK6c";
    /**
     * 证书路径
     */
    private static String cert_p12_path = "apiclient_cert.p12";



    /**
     * 支付  微信
     * @param body   订单内容主题
     * @param out_trade_no 订单号
     * @param total_fee   订单价格
     * @param roleType 1:用户端，   2：司机端
     * @return   json 串
     */
    public static String pay(String body, String out_trade_no, String total_fee, Integer roleType) throws UnsupportedEncodingException {
//        total_fee = "0.01";
        BigDecimal totalFee = new BigDecimal(total_fee).multiply(new BigDecimal(100));
        if (ObjectUtil.notEqual(AppConsts.USER_ROLE_TYPE_1, roleType) && ObjectUtil.notEqual(AppConsts.USER_ROLE_TYPE_2, roleType)) {
            throw new CustomApiException("参数有误");
        }
        Console.log("=================微信开始测试========================");
        //body = new String(body.getBytes("ISO8859-1"),"UTF-8");

        String str = "https://api.mch.weixin.qq.com/pay/unifiedorder";
//        Map<String, Object> params = new HashMap<>();
        SortedMap<Object, Object> params = new TreeMap<>();
        String nonce_str = new Long(DateUtil.date().getTime()).toString();
//        StringBuffer sb = new StringBuffer();
//        sb.append("appid=" + (roleType.equals(AppConsts.USER_ROLE_TYPE_1) ? userAppid : driverAppid))
//            .append("&body=" + body)
//            .append("&fee_type=CNY")
//            .append("&mch_id=" + mchId)
//            .append("&nonce_str=" + nonce_str)
//            .append("&notify_url=http://www.hzjrsy.com/yunqiao/api/order/wechatpaySuccessCallBack")
//            .append("&out_trade_no=" + out_trade_no)
//            .append("&sign_type=MD5")
//            .append("&spbill_create_ip=47.92.132.196")
//            .append("&total_fee=" + total_fee)
//            .append("&trade_type=APP")
//            .append("&key=" + key)
//            ;
//        Console.log(sb);
        //注：MD5签名方式
//        String sign = MD5Util.getMD5Format(sb.toString()).toUpperCase();
//        Console.log("sign==========");
//        Console.log(sign);
        params.put("appid", (roleType.equals(AppConsts.USER_ROLE_TYPE_1) ? userAppid : driverAppid));
        params.put("body", body);
        params.put("fee_type", "CNY");
        params.put("mch_id", mchId);
        params.put("nonce_str", nonce_str);
        params.put("notify_url", SysConfig.host+"yunqiao/api/order/wechatpaySuccessCallBack");
        params.put("out_trade_no", out_trade_no);
        params.put("sign_type", "MD5");
        params.put("spbill_create_ip", "47.92.132.196");
        params.put("total_fee", totalFee.longValue()+"");
        params.put("trade_type", "APP");
        String sign =createSign(params,key);
        Console.log("sign=========="+sign);
        params.put("sign", sign);
        String result = HttpUtil.post(str, XmlUtil.mapToXmlStr(params, "xml"));

        Console.log(result);

        Map<String, Object> resultMap = XmlUtil.xmlToMap(result);


        //重新签名 给调起支付用
        String timestamp = new Long(DateUtil.date().getTime() / 1000).toString();
        Object nonceStr = resultMap.get("nonce_str");
//        sb = new StringBuffer();
//        sb.append("appid=" + (roleType.equals(AppConsts.USER_ROLE_TYPE_1) ? userAppid : driverAppid))
//            .append("&noncestr=" + nonceStr)
//            .append("&package=Sign=WXPay")
//            .append("&partnerid=" + mchId)
//            .append("&prepayid=" + resultMap.get("prepay_id"))
//            .append("&timestamp=" + timestamp)
//            .append("&key=" + key)
//        ;
//        String newSign = MD5Util.getMD5Format(sb.toString()).toUpperCase();

        SortedMap<Object, Object> map = new TreeMap<>();
        map.put("timestamp", timestamp);
        map.put("package", "Sign=WXPay");
        map.put("appid", resultMap.get("appid"));
        map.put("partnerid", resultMap.get("mch_id"));
        map.put("prepayid", resultMap.get("prepay_id"));
        map.put("noncestr", nonceStr);
        String newSign =createSign(map,key);
        map.put("sign", newSign);
        //
        return JSONUtil.toJsonStr(map);
    }
    /**
     * 支付  微信
     * @param body   订单内容主题
     * @param out_trade_no 订单号
     * @param total_fee   订单价格
     * @param roleType 1:用户端，   2：司机端
     * @return   json 串
     */
    public static String payJSAPI(String body, String out_trade_no, String total_fee, Integer roleType,String openId) throws UnsupportedEncodingException {
//        total_fee = "0.01";
        if (ObjectUtil.notEqual(AppConsts.USER_ROLE_TYPE_1, roleType) && ObjectUtil.notEqual(AppConsts.USER_ROLE_TYPE_2, roleType)) {
            throw new CustomApiException("参数有误");
        }
        BigDecimal totalFee = new BigDecimal(total_fee).multiply(new BigDecimal(100));
        Console.log("=================微信开始测试========================");
        //body = new String(body.getBytes("ISO8859-1"),"UTF-8");
        String str = "https://api.mch.weixin.qq.com/pay/unifiedorder";
        SortedMap<Object, Object> params = new TreeMap<>();
        String nonce_str = new Long(DateUtil.date().getTime()).toString();
        //注：MD5签名方式
        params.put("appid", (roleType.equals(AppConsts.USER_ROLE_TYPE_1) ? wx_small_procedures_user_appid : wx_small_procedures_driver_appid));
        params.put("body", body);
        params.put("fee_type", "CNY");
        params.put("mch_id", mchId);
        params.put("nonce_str", nonce_str);
        params.put("notify_url", SysConfig.host+"yunqiao/api/order/wechatpaySuccessCallBack");
        params.put("out_trade_no", out_trade_no);
        params.put("sign_type", "MD5");
        params.put("spbill_create_ip", "47.92.132.196");
        params.put("total_fee", totalFee.longValue()+"");
        params.put("trade_type", "JSAPI");
        params.put("openid", openId);
        String sign =createSign(params,key);
        Console.log("sign=========="+sign);
        params.put("sign", sign);
        String result = HttpUtil.post(str, XmlUtil.mapToXmlStr(params, "xml"));
        Console.log(result);
        Map<String, Object> resultMap = XmlUtil.xmlToMap(result);
        String timestamp = new Long(DateUtil.date().getTime() / 1000).toString();
        Object nonceStr = resultMap.get("nonce_str");
        SortedMap<Object, Object> map = new TreeMap<>();
        map.put("timeStamp", timestamp);
        map.put("package", "prepay_id="+resultMap.get("prepay_id"));
        map.put("appId", resultMap.get("appid"));
//        map.put("partnerid", resultMap.get("mch_id"));
        map.put("signType", "MD5");
        map.put("nonceStr", nonceStr);
        String newSign = createSign(map,key);
        map.put("outTradeNo",out_trade_no);
        map.put("paySign", newSign);
        Console.log("newSign=========="+newSign);
        String pay_body=JSONUtil.toJsonStr(map);
        Console.log(pay_body);
        return pay_body;
    }

    /**
     * @Description：创建sign签名
     *            编码格式
     * @param parameters
     *            请求参数
     * @return
     */
    public static String createSign( SortedMap<Object, Object> parameters, String wxPayKey)
    {
        StringBuffer sb = new StringBuffer();
        Set es = parameters.entrySet();
        Iterator it = es.iterator();
        while (it.hasNext())
        {
            Map.Entry entry = (Map.Entry) it.next();
            String k = (String) entry.getKey();
            Object v = entry.getValue();
            if (null != v && !"".equals(v) && !"sign".equals(k) && !"key".equals(k))
            {
                sb.append(k + "=" + v + "&");
            }
        }
        sb.append("key=" + wxPayKey);
        Console.log("param md5=========="+sb.toString());
//        String sign = MD5Util.getMD5Format(sb.toString()).toUpperCase();
        String sign = com.yunqiao.common.utils.MD5Util.MD5Encode(sb.toString(), "UTF-8").toUpperCase();
        return sign;
    }
    /**
     * 退款
     * @param out_trade_no 订单号
     * @param out_refund_no 退款订单号   动态生成，保证不重复
     * @param total_fee     订单金额
     * @param refund_fee    退款金额
     * @param roleType      1：用户   2：司机 3 微信小程序用户
     * @return
     */
    public static String refund(String out_trade_no, String out_refund_no, String total_fee, String refund_fee, Integer roleType,Integer payType) throws Exception {
//        total_fee = "1";
//        refund_fee = "1";
        BigDecimal refundFee = new BigDecimal(refund_fee).multiply(new BigDecimal(100));
        BigDecimal totalFee = new BigDecimal(total_fee).multiply(new BigDecimal(100));
        String url = "https://api.mch.weixin.qq.com/secapi/pay/refund";
        if (ObjectUtil.notEqual(AppConsts.USER_ROLE_TYPE_1, roleType) && ObjectUtil.notEqual(AppConsts.USER_ROLE_TYPE_2, roleType)) {
            throw new CustomApiException("参数有误");
        }
        Console.log("=================微信退款开始测试========================");
        Map<String, Object> params = new HashMap<>();
        String nonce_str = new Long(DateUtil.date().getTime()).toString();
        StringBuffer sb = new StringBuffer();
        String appid =(roleType.equals(AppConsts.USER_ROLE_TYPE_1) ? userAppid : driverAppid);
        if(payType!=null&&payType ==1){
            appid = (roleType.equals(AppConsts.USER_ROLE_TYPE_1) ? wx_small_procedures_user_appid : wx_small_procedures_driver_appid);
        }
        sb.append("appid=" + appid)
            .append("&fee_type=CNY")
            .append("&mch_id=" + mchId)
            .append("&nonce_str=" + nonce_str)
            .append("&notify_url="+SysConfig.host+"yunqiao/api/order/wechatrefundSuccessCallBack")
            .append("&out_refund_no=" + out_refund_no)
            .append("&out_trade_no=" + out_trade_no)
            .append("&refund_fee=" + refundFee.intValue())
            .append("&sign_type=MD5")
            .append("&total_fee=" + totalFee.intValue())
            .append("&key=" + key)
        ;
        //注：MD5签名方式
//        String sign = MD5Util.getMD5Format(sb.toString()).toUpperCase();
        String sign = com.yunqiao.common.utils.MD5Util.MD5Encode(sb.toString(), "UTF-8").toUpperCase();
        Console.log("sign==========");
        Console.log(sign);
        params.put("appid",appid);
        params.put("fee_type", "CNY");
        params.put("mch_id", mchId);
        params.put("nonce_str", nonce_str);
        params.put("sign", sign);
        params.put("sign_type", "MD5");
        params.put("out_trade_no", out_trade_no);
        params.put("out_refund_no", out_refund_no);
        params.put("total_fee", totalFee.intValue());
        params.put("refund_fee", refundFee.intValue());
        //回调地址
        params.put("notify_url", SysConfig.host+"yunqiao/api/order/wechatrefundSuccessCallBack");

        //指定读取证书格式为PKCS12
        KeyStore keyStore = KeyStore.getInstance("PKCS12");
        //读取本机存放的PKCS12证书文件
        ClassPathResource resource = new ClassPathResource(cert_p12_path);
        try {
            //指定PKCS12的密码(商户ID)
            keyStore.load(resource.getStream(), mchId.toCharArray());
        } finally {

        }
        SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, mchId.toCharArray()).build();
        //指定TLS版本
        SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[]{"TLSv1"}, null, SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
        //设置httpclient的SSLSocketFactory
        CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();

        HttpPost httppost = new HttpPost(url);
        StringEntity reqEntity = new StringEntity( XmlUtil.mapToXmlStr(params, "xml"), "UTF-8");
        httppost.setEntity(reqEntity);

        CloseableHttpResponse response = httpclient.execute(httppost);
        String result = EntityUtils.toString(response.getEntity(), "UTF-8");
        Console.log(result);
        return result;
    }
}
